package com.billing.web.controller.common.tag;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.MessageDigest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;

/**
 * 
 * @author badqiu
 * 
 *         modify by willothe at 2010.11.03 动态执行override里面的JSP代码（回调）
 * 
 */
public class BlockTag extends TagSupport {

	private static final long serialVersionUID = -8246166191638588615L;

	private PageContext pageContext;
	private static Object cacheIdLock = new Object();
	private String separator;
	private String cacheDir;
	private String callback;
	private StringBuffer b8;

	private String name;

	public BlockTag() {
		separator = System.getProperty("file.separator");
		cacheDir = "WEB-INF" + separator + "jsp_eval_cache";
		b8 = null;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public void setPageContext(PageContext pagecontext) {
		pageContext = pagecontext;
	}

	public String getCallback() {
		return callback;
	}

	public void setCallback(String callback) {
		this.callback = callback;
	}

	/**
	 * @return EVAL_BODY_INCLUDE or EVAL_BODY_BUFFERED or SKIP_BODY
	 */
	@Override
	public int doStartTag() throws JspException {
		return getOverriedContent() == null ? EVAL_BODY_INCLUDE : SKIP_BODY;
	}

	/**
	 * @return EVAL_PAGE or SKIP_PAGE
	 */
	@Override
	public int doEndTag() throws JspException {
		String overriedContent = getOverriedContent();
		if(overriedContent == null) {
			return EVAL_PAGE;
		}
		if (callback != null) {
			
			String webRoot = getDir();
			String path = cacheDir;
			boolean flag = !pageContext.getOut().isAutoFlush();
			
			if (!webRoot.endsWith("\\") && !webRoot.endsWith("/"))
				webRoot = (new StringBuilder()).append(webRoot).append(separator)
						.toString();
			
			if (!path.endsWith("\\") && !path.endsWith("/"))
				path = (new StringBuilder()).append(path).append(separator)
						.toString();
			File file = new File((new StringBuilder()).append(webRoot).append(
					path).toString());
			
			if(!file.exists() && !file.isDirectory()){
				file.mkdir();
			}
			
			if (file == null)
				throw new JspException((new StringBuilder()).append(
						"eval:could not use cache directory ").append(cacheDir)
						.toString());
			
			if (!file.isDirectory())
				throw new JspException((new StringBuilder()).append(
						"eval:could not use cache directory ").append(cacheDir)
						.toString());
			if (!file.canRead() || !file.canWrite())
				throw new JspException((new StringBuilder()).append(
						"eval:could not read/write cache directory ").append(
						cacheDir).toString());
			
			MessageDigest messagedigest;
			try {
				messagedigest = MessageDigest.getInstance("SHA");
			} catch (Exception exception3) {
				throw new JspException((new StringBuilder()).append(
						"eval: could not calculate digest. ").append(
						exception3.toString()).toString());
			}
			messagedigest.update(overriedContent.getBytes());
			byte abyte0[] = messagedigest.digest();
			b8 = new StringBuffer("00000000");
			String s4 = encode(abyte0, abyte0.length);
			path = (new StringBuilder()).append(path).append(s4).append(".jsp")
					.toString();
			boolean flag1 = true;
			synchronized (cacheIdLock) {
				File file1 = new File((new StringBuilder()).append(webRoot).append(
						path).toString());
				if (file1 == null)
					flag1 = false;
				else if (!file1.isFile())
					flag1 = false;
				else if (!file1.canRead())
					flag1 = false;
				if (!flag1)
					try {
						FileOutputStream fileoutputstream = new FileOutputStream(
								(new StringBuilder()).append(webRoot).append(path)
										.toString());
						Writer out = new OutputStreamWriter(fileoutputstream, "utf-8");
						out.write("<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\" pageEncoding=\"UTF-8\"%><%@ include file=\"/inc/taglibs.jsp\"%>");
						out.write(overriedContent);
						out.close();
					} catch (Exception exception4) {
						throw new JspException((new StringBuilder()).append(
								"eval:Could not create temp file ").append(
								exception4.getMessage()).toString());
					}
			}
			
			try {
				if (flag)
					pageContext.getOut().flush();
	
				path = getRelativeUrlPath(path);
				pageContext.include(path);
				if (flag)
					pageContext.getOut().flush();
			} catch (Exception exception1) {
				throw new JspException((new StringBuilder()).append(
						"eval:Could not include temp file ").append(
						exception1.getMessage()).toString());
			}		
			
		} else {
			try {
				pageContext.getOut().write(overriedContent);
			} catch (IOException e) {
				throw new JspException("tag output error,block name:"+name,e);
			}
			
		}
		
		dropData();		

		return EVAL_PAGE;
	}
	
	private String getOverriedContent() {
		String varName = Utils.getOverrideVariableName(name);
		return (String)pageContext.getRequest().getAttribute(varName);
	}
	
	private String getRelativeUrlPath(String path){
		
		HttpServletRequest httpservletrequest = (HttpServletRequest) (HttpServletRequest) pageContext.getRequest();
		String s = httpservletrequest.getServletPath();		
		s = s.replaceAll("/WEB-INF", "");
		path = path.replaceAll("/WEB-INF", "").replaceAll("\\\\", "/");
		
		StringBuilder sb = new StringBuilder();
		for(int i = 0,depth = s.split("[\\/]").length - 1; i < depth; i++){
			sb.append("../");
		}
		sb.append(path);
		return sb.toString();
		
	}
	private String getDir() {
		String s1 = pageContext.getServletContext().getRealPath("/");
		return getDirectory(s1);
	}

	public void release() {
		dropData();
	}

	private void dropData() {
		b8 = null;
	}

	private String getDirectory(String s) {
		if (s == null)
			return null;
		int i = s.lastIndexOf("\\");
		if (i < 0)
			i = s.lastIndexOf("/");
		if (i < 0)
			return s;
		else
			return s.substring(0, i + 1);
	}

	private String toBinaryString(byte byte0) {
		byte byte1 = byte0;
		String s = Integer.toBinaryString(byte1);
		if (byte1 < 0)
			s = s.substring(s.length() - 8);
		for (; s.length() < 8; s = (new StringBuilder()).append("0").append(s)
				.toString())
			;
		return s;
	}

	private int getChunk(String s, int i) {
		for (int j = 2; j <= 7; j++)
			b8.setCharAt(j, s.charAt((i + j) - 2));

		return Integer.parseInt(b8.toString(), 2);
	}

	private String encode(byte abyte0[], int i) {
		StringBuffer stringbuffer = new StringBuffer();
		for (int j = 0; j < i; j += 3) {
			if (j + 2 < i) {
				String s = (new StringBuilder()).append(
						toBinaryString(abyte0[j])).append(
						toBinaryString(abyte0[j + 1])).append(
						toBinaryString(abyte0[j + 2])).toString();
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s, 0)));
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s, 6)));
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s, 12)));
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s, 18)));
				continue;
			}
			if (j + 1 < i) {
				String s1 = (new StringBuilder()).append(
						toBinaryString(abyte0[j])).append(
						toBinaryString(abyte0[j + 1])).append("00").toString();
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s1, 0)));
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s1, 6)));
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s1, 12)));
				stringbuffer.append('=');
			} else {
				String s2 = (new StringBuilder()).append(
						toBinaryString(abyte0[j])).append("0000").toString();
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s2, 0)));
				stringbuffer
						.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$"
								.charAt(getChunk(s2, 6)));
				stringbuffer.append('=');
				stringbuffer.append('=');
			}
		}

		return stringbuffer.toString();
	}	
}
